package com.group9.handinhand.controller;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.group9.handinhand.controller.form.RequestCreateForm;
import com.group9.handinhand.controller.form.RequestUpdateForm;
import com.group9.handinhand.controller.form.RequestViewForm;
import com.group9.handinhand.service.CommunityService;
import com.group9.handinhand.service.RequestService;
import com.group9.handinhand.service.TagService;
import com.group9.handinhand.service.so.ActivityEnums.ActivityType;
import com.group9.handinhand.service.so.CommunityMemberSO;
import com.group9.handinhand.service.so.CommunitySO;
import com.group9.handinhand.service.so.RequestResponseSO;
import com.group9.handinhand.service.so.RequestSO;
import com.group9.handinhand.service.so.TagSO;
import com.group9.handinhand.service.so.UserSO;
import com.group9.handinhand.service.so.UserTagSO;
/**
 * A controller for request
 *
 */
@Controller
public class RequestController extends AbstractBaseController {
	
	@Autowired
	TagService tagService;
	
	@Autowired
	CommunityService communityService;
	
	@Autowired
	RequestService requestService;
	
	private List<UserSO> moderatorsList;
	private UserSO creator;
	
	@RequestMapping(value = "/requests")
	public String requests(HttpServletRequest request, Model model){
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		
		List<RequestSO> respondedRequestList = requestService.getRespondedRequestsByUser(user);
		List<RequestSO> moderatedRequestList = requestService.getModeratedRequestsByUser(user);
		model.addAttribute("respondedRequestList", respondedRequestList);
		model.addAttribute("moderatedRequestList", moderatedRequestList);
		return "listRequests";
	}
	/**
	 * 
	 * @param communityId
	 * @param requestCreateForm
	 * @param request
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/communities/{communityId}/newRequest")
	public String newRequest(@PathVariable Long communityId, RequestCreateForm requestCreateForm,  BindingResult errors, HttpServletRequest request, Model model){
		
		RequestSO so = new RequestSO();
		so.setCommunity(communityService.getCommunityById(communityId));
		requestCreateForm.setRequest(new RequestSO());
		model.addAttribute("activityTypes", ActivityType.values());
		return "newRequest";
	}
	
	@RequestMapping(value = "/communities/{communityId}/saveRequest")
	public String saveRequest(@PathVariable Long communityId, RequestCreateForm requestCreateForm,  BindingResult errors, HttpServletRequest req, Model model){
		
		validateNewRequest(requestCreateForm, errors);
		if(errors.hasErrors()){
			return newRequest(communityId, requestCreateForm, errors, req, model);
		}
		requestCreateForm.setEndDate();
		RequestSO request = requestCreateForm.getRequest();
		
		request = requestService.saveRequest(request, getUser(), communityId);
		
		List<String> selectedTags = requestCreateForm.getSelectedTagsAsList();
		
		tagService.saveRequestTags(request,selectedTags);
		
		return "redirect:/communities/" + communityId + "/requests/" + request.getId();
	}
	
	@RequestMapping(value = "/communities/{communityId}/requests")
	public String listRequestsOfCommunity(@PathVariable Long communityId, HttpServletRequest request, Model model){
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		
		CommunitySO community = communityService.getCommunityById(communityId);
		
		Set<RequestSO> requestList = community.getRequests();
		model.addAttribute("requestList", requestList);
		model.addAttribute("communityId", communityId);
		return "listRequestsOfCommunity";
	}
	
	@RequestMapping(value = "/communities/{communityId}/requests/{requestId}")
	public String viewRequest(@PathVariable Long communityId, @PathVariable Long requestId, RequestViewForm requestViewForm, HttpServletRequest req, Model model){
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		CommunityMemberSO communityMemberSO = communityService.getCommunityMemberByCommunityIdAndUserId(communityId, user.getId());
		RequestSO request = requestService.getRequestById(requestId);
		RequestSO moderatedRequest = requestService.getModeratedRequestByRequestIdAndUserId(requestId, user.getId());
		requestViewForm.setCommunityMember(communityMemberSO);
		requestViewForm.setModeratedRequest(moderatedRequest);
		requestViewForm.setRequest(request);
		requestViewForm.setWallElementsFromRequest();
		
		// Find User Tags
		List<UserTagSO> userTags = tagService.getUserTagsByUser(user);
		requestViewForm.setUserTags(userTags);
		
		// Find Requests From User Tags 
		ArrayList<Object> requestList = new ArrayList<Object>();
		for(int i=0; i<userTags.size();i++){
			requestList.addAll(requestService.getRequestsByTag(userTags.get(i)));
			}
		requestViewForm.setRequestList(requestList);
		
		
		List<RequestSO> requestListofModerated = requestService.getModeratedRequestsByUser(user);
		model.addAttribute("requestListofModerated", requestListofModerated);
		
		// Exclude Moderated request from above found
		for(int i=0; i<requestListofModerated.size();i++)
		{
		requestList.remove(requestListofModerated.get(i));
		}
		
		
		// Exclude Responded offers from above found
		List<RequestSO> requestListofResponded = requestService.getRespondedRequestsByUser(user);
		model.addAttribute("requestListofResponded", requestListofResponded);
		requestListofResponded.add(requestService.getRequestById(requestId));
		
		for(int i=0; i<requestListofResponded.size();i++)
		{
		requestList.remove(requestListofResponded.get(i));
		}
		ArrayList<RequestResponseSO> list = requestService.getRequestResponsesByUserIdAndRequestId(getUser().getId(), requestId);
		requestViewForm.setUserContributionFromList(list);
		
		return "viewRequest";
	}

	private void validateNewRequest(RequestCreateForm requestCreateForm, BindingResult errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "request.name", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingDay", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingHour", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "request.description", "required.field");
		RequestSO request = requestCreateForm.getRequest();
		if(request.getActivityType() == ActivityType.GOODS) {
			request.setService(null);
		}
		else if(request.getActivityType() == ActivityType.SERVICES) {
			request.setGoods(null);
		}
		else {
			request.setGoods(null);
			request.setService(null);
		}
	}
	
	private void validateEditedRequest(RequestUpdateForm requestUpdateForm, BindingResult errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "request.name", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingDay", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "endingHour", "required.field");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "request.description", "required.field");
		RequestSO request = requestUpdateForm.getRequest();
		if(request.getActivityType() == ActivityType.GOODS) {
			request.setService(null);
		}
		else if(request.getActivityType() == ActivityType.SERVICES) {
			request.setGoods(null);
		}
		else {
			request.setGoods(null);
			request.setService(null);
		}
		
	}
	
	@RequestMapping(value = "/communities/{communityId}/requests/{requestId}/post")
	public String post(@PathVariable Long communityId, @PathVariable Long requestId, RequestViewForm requestViewForm, HttpServletRequest request, Model model){
		
		String post = requestViewForm.getPost();
		
		UserSO user = getUser();
		
		requestService.saveRequestPost(requestId, user.getId(), post);
		
		return "redirect:/communities/{communityId}/requests/" + requestId;
	}
	
	@RequestMapping(value = "/communities/{communityId}/requests/{requestId}/respond")
	public String respond(@PathVariable Long communityId, @PathVariable Long requestId, RequestViewForm requestViewForm, HttpServletRequest req, Model model, BindingResult errors){
		
		RequestSO request = requestService.getRequestById(requestId);
		requestViewForm.setRequest(request);
		
		validateRequestOrService(requestViewForm, errors);
		if(errors.hasErrors()){
			return viewRequest(communityId, requestId, requestViewForm, req, model);
		}
		
		UserSO user = getUser();
		if(user == null){
			return "redirect:";
		}
		
		if(requestViewForm.getRequest().getActivityType() == ActivityType.SERVICES){
			requestService.saveRequestResponse(request, user.getId(), requestViewForm.getServicesAmount());
		}
		else if(requestViewForm.getRequest().getActivityType() == ActivityType.GOODS){
			requestService.saveRequestResponse(request, user.getId(), requestViewForm.getGoodsAmount());
		}
		
		return "redirect:/communities/{communityId}/requests/" + requestId;
	}
	
	@RequestMapping(value = "/communities/{communityId}/requests/{requestId}/editRequest")
	public String editRequest(@PathVariable Long communityId, @PathVariable Long requestId, RequestUpdateForm requestUpdateForm, BindingResult errors, HttpServletRequest req, Model model){
		
		RequestSO request = requestService.getRequestById(requestId);
		
		if(request != null){
			requestUpdateForm.setRequest(request);
			List<TagSO> selectedTags = tagService.getTagsByRelatedRequestId(requestId);
			moderatorsList = requestService.getModeratorsByRequestId(requestId);
			creator = request.getCreator();
			requestUpdateForm.setSelectedTagsFromList(selectedTags);
			DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
			String endingDate = df.format(request.getExpirationDate());    
			requestUpdateForm.setEndingDay(endingDate.substring(0,10));
			requestUpdateForm.setEndingHour(endingDate.substring(10));

		}

		return "updateRequest";
	}
	
	@RequestMapping(value = "/communities/{communityId}/requests/{requestId}/updateRequest", method = RequestMethod.POST)
	public String updateRequest(@PathVariable Long communityId, @PathVariable Long requestId, RequestUpdateForm requestUpdateForm, BindingResult errors, HttpServletRequest req, Model model){
		
		validateEditedRequest(requestUpdateForm, errors);
		if(errors.hasErrors()){
			return editRequest(communityId, requestId, requestUpdateForm, errors, req, model);
		}
		requestUpdateForm.setEndDate();
		RequestSO request = requestUpdateForm.getRequest();
		
		for(UserSO so : moderatorsList)
		{
			request.getModerators().add(so);
		}
		
		System.out.println("----------------------------------  " + request.getId());;
		
		request.setId(requestId);
		request.setCreator(creator);
		request.setCommunity(communityService.getCommunityById(communityId));
		requestService.updateRequest(request);
		
		List<String> selectedTags = requestUpdateForm.getSelectedTagsAsList();
		
		tagService.saveRequestTags(request,selectedTags);	
				
		return "redirect:/communities/" + communityId + "/requests/" + requestId + "/editRequest";
	}

	private void validateRequestOrService(RequestViewForm requestViewForm,  BindingResult errors) {
		if(requestViewForm.getRequest().getActivityType() == ActivityType.SERVICES){
			ValidationUtils.rejectIfEmptyOrWhitespace(errors, "servicesAmount", "Required field");
			if(requestViewForm.getRequest().getService().getRequiredNumber() - 
					requestViewForm.getRequest().getService().getRespondedAmount() < requestViewForm.getServicesAmount())
				errors.rejectValue("servicesAmount", "Amount cannot be greater than the required amount");
		}
		else if(requestViewForm.getRequest().getActivityType() == ActivityType.GOODS){
			ValidationUtils.rejectIfEmptyOrWhitespace(errors, "goodsAmount", "Required field");
			if(requestViewForm.getRequest().getGoods().getTargetAmount() - 
					requestViewForm.getRequest().getGoods().getRespondedAmount()< requestViewForm.getGoodsAmount())
				errors.rejectValue("goodsAmount", "Amount cannot be greater than the required amount");
		}
		
	}
	
}
